﻿#ifndef IPLUGINDIALOG_H
#define IPLUGINDIALOG_H

//#include <cxxabi.h>

#include <QObject>
#include <QDialog>
#include <QTabWidget>
#include <QDomDocument>
#include <QMap>
#include <QVariant>
#include <QBitArray>
#include <QDebug>
#include <QBuffer>
#include <QImageReader>
#include <QTranslator>

#include "Interface_Global.h"
#include "IPluginParam.h"
#include "FlowCellParam.h"
#include "PluginDesc.h"
#include "FlowTree.h"
#include "PluginManager.h"
#include "PluginSpec.h"
#include "IPluginOperator.h"

#include "ImageResultPreviewWidget.h"
#include "Line.h"

namespace CVV {
namespace Infrastructure {
namespace Model {
class GraphicWidgetModel;
}
}
}

using namespace CVV::Infrastructure::ExtensionSystem;
using CVV::Infrastructure::Model::GraphicWidgetModel;
using CVV::Entity::Line;

namespace CVV
{

namespace Interface
{
class IPluginParam;

//class ImageResultPreviewWidget;
class INTERFACE_EXPORT IPluginDialog : public QDialog
{
    Q_OBJECT
public:

    explicit IPluginDialog(const QString &pluginCode,
                           const QString &flowId,
                           const QString &cellId,
                           const QString &cellTitle,
                           QWidget *parent = nullptr);

    ~IPluginDialog() override;
    /**
     * @brief run 运行插件主窗体
     * @return
     */
    virtual bool run()=0;
    /**
     * @brief init 打开流程时候，先内存构建Dom树，根据Dom 逐步初始化流程单元
     * @return
     */
    virtual bool init()=0;

    /**
     * @brief getPluginParam 单元参数通过插件接口获取对应具体插件信息
     * @return
     */
    virtual IPluginParam* getPluginParam()=0;
    /**
     * @brief on_updatedDom
     * 重新绘制流程时候更新流程树之后会触发
     * @return
     */
    virtual void updatedDom()=0;

    /**
     * @brief getPrevOutFlowParam 获取当前单元之前单元执行成功的输出参数 进行选择使用
     * @param dataType 数据类型
     * @return
     */
    QMap<QString, QList<FlowCellParam>> getPrevOutFlowParam(const QString &dataType = QString());

    /**
     * @brief findAllPreOutFlowTree 查找所有的前节点
     * @param lstPreFlowTree
     */
    void findAllPreOutFlowTree(const QList<FlowTree> &lstAllFlowTree, const FlowTree &paFlowTree, QList<FlowTree> &lstPreFlowTree);

    /**
     * @brief get set 流程树
     * @return
     */
    QMap<QString, FlowTree> getFlowTree() const;
    void setFlowTree(const QMap<QString, FlowTree> &flowTree);

    /**
     * @brief getFlowCellParam 获取流程单元数据
     * @return
     */
    QList<FlowCellParam> getFlowCellParam();

    /**
     * @brief getFlowCellAlgorithmParam 获取算法参数
     * @return
     */
    QList<FlowCellParam> getFlowCellAlgorithmParam();

    /**
     * @brief getFlowParam 获取当前单元之前单元执行成功的输出参数 进行选择使用
     * @param dataType 数据类型
     * @return 返回流程所以单元数据 key 单元名称
     */
    QMap<QString, QList<FlowCellParam>> getFlowParam();

    /**
     * @brief 通过输入插件路径获取对应的值
     * @param pluginParamPath 插件Code.插件单元ID.参数属性名称
     * @return
     */
    QList<QPointF> getPreAllBasePoint();
    /**
     * @brief 设置自定义参数声明类型
     * @param param <type, code, value>
     */
    void setDynamicParamDefine(const QList<std::tuple<QString, QString, QString>> &pairList);

    /**
     * @brief 获得圆链表
     * @param pluginParamPath
     */
    QList<Circular> getListCircleFromParamData(const QString &pluginParamPath);

    template<class T >
    T getPluginParamData(const QString &pluginParamPath)
    {
        T value;
        QStringList paths= pluginParamPath.split(".");
        if(3 <= paths.size())
        {
            QString pluginCode = paths[0];
            QString cellId = paths[1];
            QString paramName = paths[2];
            auto obj = PluginManager::getObjectByName(pluginCode);
            IPluginOperator *opt = dynamic_cast<IPluginOperator *>(obj);
            if(opt != nullptr)
            {
                QMap<QString, QMap<QString, std::shared_ptr<IPluginDialog>>> flowPDMap=
                        opt->flowCellDialogs();
                if(flowPDMap.contains(m_flowId) && flowPDMap[m_flowId].contains(cellId))
                {
                    IPluginParam *param = flowPDMap[m_flowId][cellId]->getPluginParam();
                    if (param)
                    {
                        if (param->hasDynamicProperty(paramName))
                        {
                            value = param->getDynamicPropertyValue(paramName).value<T>();
                        }
                        else
                        {
                            value = param->property(paramName.toStdString().c_str()).value<T>();
                        }
                    }
                }
                else if (flowPDMap.contains(m_strSubFlowId) && flowPDMap[m_strSubFlowId].contains(cellId))
                {
                    IPluginParam *param = flowPDMap[m_strSubFlowId][cellId]->getPluginParam();
                    if (param)
                    {
                        if (param->hasDynamicProperty(paramName))
                        {
                            value = param->getDynamicPropertyValue(paramName).value<T>();
                        }
                        else
                        {
                            value = param->property(paramName.toStdString().c_str()).value<T>();
                        }
                    }
                }
                else if (m_mapSubprocessParamValue.contains(paramName))     // 从主流程传递过来的参数
                {
                    value = m_mapSubprocessParamValue.value(paramName).value<T>();
                }
            }
        }
        return  value;
    }

    /**
     * @brief changeLanguage 切换语言
     * @param language
     */
    virtual void changeLanguage(const QString &language) = 0;

    /**
     * @brief retranslateUi 翻译UI
     */
    virtual void retranslateUi() = 0;

    /**
     * @brief 获取插件的时间是否显示
     * @return
     */
    virtual bool runtimeIsVisible() = 0;

    /**
     * @brief 获取每个插件的graphicsitem
     * @return
     */
    virtual ImageViewPixmapItem* getGraphicViewPtr() = 0;

    /**
     * @brief 获取每个插件的graphicview所属的widget
     * @return
     */
    virtual QWidget *getGraphicWidgetPtr() = 0;

    /**
     * @brief 获取插件标题
     * @return
     */
    QString getWindowTitle() const {return m_title;}
    void setWindowTitle(const QString title){m_title = title;}

    /**
     * @brief 获取每个插件的数据模型
     * @return
     */
    std::shared_ptr<GraphicWidgetModel> getGraphicViewModel() { return m_paintModel; }

    /**
     * @brief engineRunFinished 引擎运行结果
     * @param image
     * @param elapsedTime
     * @param pResultOutput
     * @param bSuccess
     */
    virtual void engineRunFinished(std::shared_ptr<CVV::Interface::IPluginParam> pResultOutput, bool bSuccess) = 0;

    /**
     * @brief getPluginParams
     * @return
     */
    QMap<QString, QJsonArray> getPluginParams() const;

    /**
     * @brief setToolName 设置工具名称
     * @param name
     */
    void setToolName(const QString &name);

    /**
     * @brief setDefectPinYinCode 设置缺陷拼音码
     * @param lstCode
     */
    void setDefectPinYinCode(const QStringList &lstCode);


    /**
     * @brief clearData 清除界面每次运行的结果数据
     */
    virtual void clearData() {}

    /**
     * @brief setSubprocessFlowCellParam 设置子流程内的流程参数列表
     * @param mapData
     */
    void setSubprocessFlowCellParam(const QHash<QString, QList<FlowCellParam>> &mapData);

    /**
     * @brief setSubprocessInputParam 设置输入到子流程的参数
     * @param hashData
     */
    void setSubprocessInputParam(const QHash<QString, QList<FlowCellParam>> &hashData);

    /**
     * @brief setSubprocessParamValue 设置输入到子流程的参数值
     * @param mapData
     */
    void setSubprocessParamValue(const QMap<QString, QVariant> &mapData);

public slots:
    /**
     * @brief slotUpdateSubprocessFlowTree 子流程树更新
     * @param flowId    主流程Id
     * @param cellId    主流程中子流程节点Id
     * @param subFlowId 子流程Id
     */
    void slotUpdateSubprocessFlowTree(const QString &flowId, const QString &cellId, const QString &subFlowId);

protected:
    void closeEvent(QCloseEvent *) override;
    void showEvent(QShowEvent *) override;

    /**
     * @brief pluginHelpPage 返回插件帮助页面
     * @return
     */
    QWidget* pluginHelpPage();

signals:
    void sigClose();
    void sigRunTime(float runtime);
    void sigSendModelToMainWin(std::shared_ptr<GraphicWidgetModel> model);


protected:
    /**
     * @brief 流程ID m_flowId
     */
    QString m_flowId;
    /**
     * @brief 单元Id m_cellId
     */
    QString m_cellId;
    /**
     * @brief 单元标题
     */
    QString m_cellTitle;
    /**
     * @brief 插件Code
     */
    QString m_pluginCode;

    /**
     * @brief 标题栏名称
     */
    QString m_title;

    QString m_strToolName;      // 工具名称

    std::shared_ptr<GraphicWidgetModel> m_paintModel{nullptr};
    ImageViewPixmapItem* m_curItem{nullptr};

    QTranslator *m_translator{nullptr};

    QStringList m_lstDefectPinYinCode;          // 缺陷拼音码

    QTranslator* m_pTranslator{nullptr};        // 翻译器

    QHash<QString, QList<FlowCellParam>> m_hashSubprocessFlowCellParam;           // 子流程内的流程参数<pluginName_id, >
    QHash<QString, QList<FlowCellParam>> m_hashSubprocessInputParam;              // 输入到子流程的参数<pluginName_id, >
    QMap<QString, QVariant> m_mapSubprocessParamValue;                            // 输入到子流程的参数值<动态属性名， 值>
    QString m_strSubFlowId;                                                       // 子流程id

private:
    /**
     * @brief init 初始信息 包括 流程单元插件信息 在动态加载流程单元插件信息来生成工具箱插件
     * @return 返回插件流程插件信息列表
     */
     bool initPlugin();

     /**
      * @brief connectSignalSlots 信号槽链接
      */
     void connectSignalSlots();

private:
     /**
      * @brief 单元参数信息
      */
    QMap<QString, QJsonArray> m_pluginParams;
    /**
     * @brief 流程Tree
     */
    QMap<QString, FlowTree> m_flowTree;

};
}

}



#endif // IPLUGINDIALOG_H
